package cn.bigfire.wzdj.pojo.bo;


import cn.hutool.core.util.ByteUtil;
import cn.hutool.core.util.HexUtil;
import cn.bigfire.wzdj.util.IdMaps;

public class WZDJHeader {

    public static final int HEADER_LENGTH = 8;
    public static final int MAGIC_NUMBER = 1;
    public static final int CURR_VERSION = 0;

    private byte[] headerBytes;

    private int magic = 1;
    private int version = 0;

    private int serialize = 2;
    private int heart = 0;
    private int crc = 0;
    private int batch = 0;
    private int compress = 0;

    private byte byte4 = 0;

    private int id = 0;
    private int time = 0;//heart==1时
    private String name = IdMaps.getTypeById(id);



    private WZDJHeader(){
        this.headerBytes = new byte[HEADER_LENGTH];
        this.magic = MAGIC_NUMBER;
        this.version = CURR_VERSION;

        this.setSerializeType(0);
        this.setHeartbeat(false);
        this.setNeedCRC(false);
        this.setBatch(false);
        this.setCompressType(0);

        this.byte4 = 0;

        this.setId(0);
        this.setTime(0);
        this.setName(IdMaps.getTypeById(id));
    }

    public WZDJHeader(byte[] headerBytes) {
        if (headerBytes.length != HEADER_LENGTH) {
            throw new RuntimeException("headerBytes length must be " + HEADER_LENGTH);
        }
        this.headerBytes = headerBytes;
        this.magic = headerBytes[0];
        this.version = headerBytes[1];

        this.serialize = getSerializeType();
        this.heart = isHeartbeat() ? 1 : 0;
        this.crc = isNeedCRC() ? 1 : 0;
        this.batch = isBatch() ? 1 : 0;
        this.compress = getCompressType();

        this.byte4 = headerBytes[3];

        byte[] byte4To8 = cn.bigfire.wzdj.util.ByteUtil.subBetween(headerBytes, 4, 8);
        if (heart == 1) {
            this.time = ByteUtil.bytesToInt(byte4To8);
            this.name = "心跳包";
        } else {
            this.id = ByteUtil.bytesToInt(byte4To8);
            this.name = IdMaps.getTypeById(id);
        }

    }


    public static WZDJHeader of(byte[] headerBytes) {
        if (headerBytes.length != HEADER_LENGTH) {
            throw new RuntimeException("headerBytes length must be " + HEADER_LENGTH);
        }
        return new WZDJHeader(headerBytes);
    }

    public static WZDJHeader ofById(int id){
        WZDJHeader wzdjHeader = new WZDJHeader();
        wzdjHeader.setId(id);
        return wzdjHeader;
    }


    // getter
    public byte[] getHeaderBytes() {
        headerBytes = new byte[HEADER_LENGTH];
        headerBytes[0] = (byte) magic;
        headerBytes[1] = (byte) version;
        headerBytes[2] = (byte) (serialize << 5 | heart << 4 | crc << 3 | batch << 2 | compress);
        headerBytes[3] = 0;

        if (heart == 1) {
            byte[] bytes = ByteUtil.intToBytes(time);
            System.arraycopy(bytes, 0, headerBytes, 4, 4);
        }else {
            byte[] bytes = ByteUtil.intToBytes(id);
            System.arraycopy(bytes, 0, headerBytes, 4, 4);
        }

        return headerBytes;
    }
    public int getSerializeType() {
        return (96 & headerBytes[2]) >>> 5;
    }

    public boolean isHeartbeat() {
        return 16 == (16 & headerBytes[2]);  //2的4次方 16表示第5位0|1
    }

    public boolean isNeedCRC() {
        return 8 == (8 & headerBytes[2]);  //2的立方 8表示第4位0|1
    }

    public boolean isBatch() {
        return 4 == (4 & headerBytes[2]);  //2平方 4表示第3位0|1
    }

    public int getCompressType() {
        return 3 & headerBytes[2];
    }

    //set
    public void setSerializeType(int serializeType) {
        headerBytes[2] = (byte) (headerBytes[2] | (serializeType << 5));
    }
    public void setHeartbeat(boolean heartbeat) {
        headerBytes[2] = (byte) (headerBytes[2] | (heartbeat ? 16 : 0));
    }
    public void setNeedCRC(boolean needCRC) {
        headerBytes[2] = (byte) (headerBytes[2] | (needCRC ? 8 : 0));
    }
    public void setBatch(boolean batch) {
        headerBytes[2] = (byte) (headerBytes[2] | (batch ? 4 : 0));
    }
    public void setCompressType(int compressType) {
        headerBytes[2] = (byte) (headerBytes[2] | compressType);
    }


    @Override
    public String toString() {
        byte[] byte4To8 = cn.bigfire.wzdj.util.ByteUtil.subBetween(headerBytes, 4, 8);
        int idOrTime = ByteUtil.bytesToInt(byte4To8);
        String byte3Decode  = String.format("serialize=%s,heart=%s,crc=%s,batch=%s,compress=%s", getSerialize(), getHeart(), getCrc(), getBatch(), getCompressType());

        String hex1 = String.format("%02x", headerBytes[0] & 0xFF);
        String hex2 = String.format("%02x", headerBytes[1] & 0xFF);
        String hex3 = String.format("%02x", headerBytes[2] & 0xFF);
        String hex4 = String.format("%02x", headerBytes[3] & 0xFF);
        String hex4To8 = HexUtil.encodeHexStr(byte4To8);
        String headerFormat = String.format("{[%s]=%s,[%s]=%s,[%s]={%s},[%s]=%s,[%s]=%s}",
                hex1, getMagic(),
                hex2, getVersion(),
                hex3, byte3Decode,
                hex4, getByte4(),
                hex4To8, idOrTime);

//        String headerFormat = String.format("{[%s]={%s},[%s]=%s}",
//                hex3, byte3Decode,
//                hex4To8, idOrTime);

        return headerFormat;
    }

    //get set
    public void setHeaderBytes(byte[] headerBytes) {
        this.headerBytes = headerBytes;
    }

    public int getMagic() {
        return magic;
    }

    public void setMagic(int magic) {
        this.magic = magic;
    }

    public int getVersion() {
        return version;
    }

    public void setVersion(int version) {
        this.version = version;
    }

    public int getSerialize() {
        return serialize;
    }

    public void setSerialize(int serialize) {
        this.serialize = serialize;
    }

    public int getHeart() {
        return heart;
    }

    public void setHeart(int heart) {
        this.heart = heart;
    }

    public int getCrc() {
        return crc;
    }

    public void setCrc(int crc) {
        this.crc = crc;
    }

    public int getBatch() {
        return batch;
    }

    public void setBatch(int batch) {
        this.batch = batch;
    }

    public int getCompress() {
        return compress;
    }

    public void setCompress(int compress) {
        this.compress = compress;
    }


    public byte getByte4() {
        return byte4;
    }

    public void setByte4(byte byte4) {
        this.byte4 = byte4;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public int getTime() {
        return time;
    }

    public void setTime(int time) {
        this.time = time;
    }

    public String getName() {
        return IdMaps.getTypeById(id);
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getZhName(){
//        return BaiDuTranslator.translate(getName());//每天可使用的测试有限
//        return LibreTranslateOTT.translate(getName());//本地OTT环境
        return getName();//原样返回
    }
}

